#region "WebConfigurationService"

/*
 * ####     Developer Name : Wang Yucai
 * 
 * ####     Development Tool : Microsoft VisualStudio 2010 Ultimate Edition
 * 
 * ####     Create Time : 2014-07-14 15:37:50
 * 
 * ####     Namespace : Masterduner.SourceStudio.Practices.DevelopmentLibrary.Web.Configuration
 * 
 * ####     Type Name : WebConfigurationService
 * 
 * ####     Full Name : Masterduner.SourceStudio.Practices.DevelopmentLibrary.Web.Configuration.WebConfigurationService
 * 
 * ####     Machine Name : GLCHQWYCWINW7
 * 
 * ####     UserName : GUOCOLAND/wangyucai
 * 
 * ####     CLR Version : 4.0.30319.18444
 * 
 * ####     Target Framework Version : 4.0
 */

#endregion

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Web.Configuration;
using Masterduner.SourceStudio.Practices.DevelopmentLibrary.Configuration;
using Masterduner.SourceStudio.Practices.DevelopmentLibrary.Web.Runtime;
using Config = System.Configuration.Configuration;

namespace Masterduner.SourceStudio.Practices.DevelopmentLibrary.Web.Configuration
{
    /// <summary>
    /// <para>Masterduner.SourceStudio.Practices.DevelopmentLibrary.Web.Configuration.WebConfigurationService</para>
    /// <para>
    /// 提供了访问Web.Config的方法。
    /// </para>
    /// </summary>
    /// <remarks>
    /// <para>Target Framework Version : 4.0</para>
    /// </remarks>
    public class WebConfigurationService : ConfigurationService
    {
        private static readonly CacheItemRemovedCallback callback = new CacheItemRemovedCallback(GlobalWebConfigurationCacheDependency.CacheRemoveCallback);

        #region Constructor

        /// <summary>
        /// <para>构造函数：</para>
        /// <para>初始化一个<see cref="WebConfigurationService" />对象实例。</para>
        /// </summary>
        public WebConfigurationService()
        {
        }

        #endregion

        #region FindInCacheService
        /// <summary>
        /// 从缓存区中搜索配置对象。
        /// </summary>
        /// <typeparam name="T">缓存对象实例。</typeparam>
        /// <param name="sectionName">自定义配置节（组）名称。</param>
        /// <returns><typeparamref name="T"/>类型的缓存对象实例。</returns>
        protected override T FindInCacheService<T>(string sectionName)
        {
            object cacheData = HttpRuntime.Cache[sectionName];
            return cacheData.IsNull() ? null : cacheData.ForceTo<T>();
        }
        #endregion

        #region SaveInCacheService
        /// <summary>
        /// 将指定名称配置对象写入缓存。
        /// </summary>
        /// <param name="sectionName">配置节（组）名称。</param>
        /// <param name="cacheData">需要缓存的配置数据。</param>
        /// <param name="dependencies">缓存依赖文件数组。</param>
        protected virtual void SaveInCacheService(string sectionName, object cacheData, string[] dependencies)
        {
            HttpRuntime.Cache.Insert(
                sectionName,
                cacheData,
                new CacheDependency(dependencies),
                Cache.NoAbsoluteExpiration,
                new TimeSpan(0, 30, 0), 
                CacheItemPriority.Normal, 
                callback);
        }
        #endregion

        #region GetWebConfiguration
        /// <summary>
        /// 获取web.config中的配置对象。
        /// </summary>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        public virtual Config GetWebConfiguration()
        {
            return this.GetAppConfiguration();
        }
        #endregion

        #region GetAppConfiguration
        /// <summary>
        /// 获取web.config中的配置对象。
        /// </summary>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        public override Config GetAppConfiguration()
        {
            Debug.WriteLine("WebConfigurationService::GetAppConfiguration::load web.config!");
            return WebConfigurationManager.OpenWebConfiguration(null, AspContextVariables.Context.SiteName);
        }
        #endregion

        #region GetSectionInWebConfig
        /// <summary>
        /// 获取web.config配置文件中的用户自定义配置。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的类型。</typeparam>
        /// <param name="sectionName">自定义配置节名称。</param>
        /// <returns><typeparamref name="TSection"/>类型的<see cref="ConfigurationSection"/>对象实例。</returns>
        public virtual TSection GetSectionInWebConfig<TSection>(string sectionName)
            where TSection : ConfigurationSection
        {
            return base.GetSectionInAppConfig<TSection>(sectionName);
        }
        #endregion

        #region GetSectionGroupInWebConfig
        /// <summary>
        /// 从web.config中获取名称为<paramref name="sectionGroupName"/>的配置节组。
        /// </summary>
        /// <typeparam name="TSectionGroup">继承自<see cref="ConfigurationSectionGroup"/>的类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <returns><typeparamref name="TSectionGroup"/>配置节组对象实例。</returns>
        public virtual TSectionGroup GetSectionGroupInWebConfig<TSectionGroup>(string sectionGroupName)
            where TSectionGroup : ConfigurationSectionGroup
        {
            return base.GetSectionGroupInAppConfig<TSectionGroup>(sectionGroupName);
        }
        #endregion

        #region OpenMappedWebConfiguration
        /// <summary>
        /// 打开映射的Web配置文件。
        /// </summary>
        /// <param name="filePath">配置文件路径。</param>
        /// <param name="fileName">配置文件名称。</param>
        /// <param name="virtualDirectory">虚拟目录名称。</param>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        protected virtual Config OpenMappedWebConfiguration(string filePath, string fileName, string virtualDirectory = "/UserConfigurations")
        {
            VirtualDirectoryMapping mapping = new VirtualDirectoryMapping(filePath, false, fileName);
            WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
            fileMap.VirtualDirectories.Add(virtualDirectory, mapping);
            return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, virtualDirectory, AspContextVariables.Context.SiteName);
        }
        #endregion

        #region GetDevLibConfiguration
        /// <summary>
        /// 获取开发库默认配置文件中的配置对象。
        /// </summary>
        /// <param name="devlibConfigPath">开发库默认配置文件路径。</param>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        protected virtual Config GetDevLibConfiguration(out string devlibConfigPath)
        {
            devlibConfigPath = string.Empty;
            Debug.WriteLine("WebConfigurationService::GetDevLibConfiguration::start to load DevLib's default configuration file!");
            FileInfo configurationFileInfo = base.GetDevLibConfigurationFileInfo();
            if (configurationFileInfo.IsNull() || !configurationFileInfo.Exists)
            {
                Debug.WriteLine("WebConfigurationService::GetDevLibConfiguration::{0}", configurationFileInfo.NotIsNull() ? configurationFileInfo.FullName : "configuration fileinfo is null");
                return null;
            }
            else
            {
                devlibConfigPath = configurationFileInfo.FullName;
                return this.OpenMappedWebConfiguration(configurationFileInfo.Directory.FullName, configurationFileInfo.Directory.Name, "/DevLibs_Configuration");
            }
        }

        /// <summary>
        /// 获取开发库默认配置文件中的配置对象。
        /// </summary>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        public override Config GetDevLibConfiguration()
        {
            string filePath = string.Empty;
            return this.GetDevLibConfiguration(out filePath);
        }
        #endregion

        #region GetSectionInDevLibConfig
        /// <summary>
        /// 从开发库默认配置文件中获取名称为<paramref name="sectionName"/>的配置节。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的<typeparamref name="TSection"/>类型对象实例。</typeparam>
        /// <param name="sectionName">配置节名称。</param>
        /// <returns><typeparamref name="TSection"/>配置节对象实例。</returns>
        public override TSection GetSectionInDevLibConfig<TSection>(string sectionName)
        {
            string filePath = string.Empty;
            return this.GetSectionInDevLibConfig<TSection>(sectionName, out filePath);
        }

        /// <summary>
        /// 从开发库默认配置文件中获取名称为<paramref name="sectionName"/>的配置节。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的<typeparamref name="TSection"/>类型对象实例。</typeparam>
        /// <param name="sectionName">配置节名称。</param>
        /// <param name="devlibConfigPath">开发库默认配置文件路径。</param>
        /// <returns><typeparamref name="TSection"/>配置节对象实例。</returns>
        protected virtual TSection GetSectionInDevLibConfig<TSection>(string sectionName, out string devlibConfigPath)
            where TSection : ConfigurationSection
        {
            devlibConfigPath = string.Empty;
            try
            {
                Config configuration = this.GetDevLibConfiguration(out devlibConfigPath);
                if (configuration.IsNull())
                {
                    return null;
                }
                else
                {
                    ConfigurationSection section = configuration.Sections[sectionName];
                    return sectionName.IsNull() ? null : sectionName.ForceTo<TSection>();
                }
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region GetSectionGroupInDevLibConfig
        /// <summary>
        /// 从开发库默认配置文件中搜索名称为<paramref name="sectionGroupName"/>的配置节组。
        /// </summary>
        /// <typeparam name="TSectionGroup">继承自<see cref="ConfigurationSectionGroup"/>的类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <returns><typeparamref name="TSectionGroup"/>配置节组对象实例。</returns>
        public override TSectionGroup GetSectionGroupInDevLibConfig<TSectionGroup>(string sectionGroupName)
        {
            string filePath = string.Empty;
            return this.GetSectionGroupInDevLibConfig<TSectionGroup>(sectionGroupName, out filePath);
        }

        /// <summary>
        /// 从开发库默认配置文件中搜索名称为<paramref name="sectionGroupName"/>的配置节组。
        /// </summary>
        /// <typeparam name="TSectionGroup">继承自<see cref="ConfigurationSectionGroup"/>的类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <param name="devlibConfigPath">开发库默认配置文件路径。</param>
        /// <returns><typeparamref name="TSectionGroup"/>配置节组对象实例。</returns>
        protected virtual TSectionGroup GetSectionGroupInDevLibConfig<TSectionGroup>(string sectionGroupName, out string devlibConfigPath)
            where TSectionGroup : ConfigurationSectionGroup
        {
            devlibConfigPath = string.Empty;
            try
            {
                Config configuration = this.GetDevLibConfiguration(out devlibConfigPath);
                if (configuration.IsNull())
                {
                    return null;
                }
                else
                {
                    ConfigurationSectionGroup sectionGroup = configuration.SectionGroups[sectionGroupName];
                    return sectionGroup.IsNull() ? null : sectionGroup.ForceTo<TSectionGroup>();
                }
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region GetUserConfiguration
        /// <summary>
        /// 从用户自定义配置文件中加载配置。
        /// </summary>
        /// <param name="sectionName">配置节（组）名称。</param>
        /// <param name="isSectionGroup">是否为配置节组。</param>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        public override Config GetUserConfiguration(string sectionName, bool isSectionGroup = false)
        {
            string filePath = string.Empty;
            return this.GetUserConfiguration(sectionName, out filePath, isSectionGroup);
        }

        /// <summary>
        /// 从用户自定义配置文件中加载配置。
        /// </summary>
        /// <param name="sectionName">配置节（组）名称。</param>
        /// <param name="userConfigPath">用户自定义配置文件路径。</param>
        /// <param name="isSectionGroup">是否为配置节组。</param>
        /// <returns><see cref="System.Configuration.Configuration"/>对象实例。</returns>
        protected virtual Config GetUserConfiguration(string sectionName, out string userConfigPath, bool isSectionGroup = false)
        {
            userConfigPath = string.Empty;
            Debug.WriteLine("WebConfigurationService::GetUserConfiguration::start to load user configuration file!");
            UserCustomizedConfigurationManager manager = new WebUserCustomizedConfigurationManager(sectionName, isSectionGroup);
            if (manager.HasUserCustomizedConfiguration && manager.UserConfigurationFile.Exists)
            {
                userConfigPath = manager.UserConfigurationFile.FullName;
                Debug.WriteLine("WebConfigurationService::GetUserConfiguration::{0}", manager.UserConfigurationFile.FullName);
                return this.OpenMappedWebConfiguration(manager.UserConfigurationFile.Directory.FullName, manager.UserConfigurationFile.Name);
            }
            else
            {
                Debug.WriteLine("WebConfigurationService::GetUserConfiguration::user configuration file not exists!");
                return null;
            }
        }
        #endregion

        #region GetSectionInUserConfig
        /// <summary>
        /// 从用户自定配置文件中获取名称为<paramref name="sectionName"/>的配置。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的类型。</typeparam>
        /// <param name="sectionName">配置节名称。</param>
        /// <returns><typeparamref name="TSection"/>类型的配置对象实例。</returns>
        public override TSection GetSectionInUserConfig<TSection>(string sectionName)
        {
            string filePath = string.Empty;
            return this.GetSectionInUserConfig<TSection>(sectionName, out filePath);
        }

        /// <summary>
        /// 从用户自定配置文件中获取名称为<paramref name="sectionName"/>的配置。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的类型。</typeparam>
        /// <param name="sectionName">配置节名称。</param>
        /// <param name="userConfigPath">用户自定义配置文件路径。</param>
        /// <returns><typeparamref name="TSection"/>类型的配置对象实例。</returns>
        protected virtual TSection GetSectionInUserConfig<TSection>(string sectionName, out string userConfigPath)
            where TSection : ConfigurationSection
        {
            userConfigPath = string.Empty;
            try
            {
                Config configuration = this.GetUserConfiguration(sectionName, out userConfigPath);
                if (configuration.IsNull())
                {
                    return null;
                }
                else
                {
                    ConfigurationSection section = configuration.Sections[sectionName];
                    return section.IsNull() ? null : section.ForceTo<TSection>();
                }
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region GetSectionGroupInUserConfig
        /// <summary>
        /// 从用户自定义配置文件中获取名称为<paramref name="sectionGroupName"/>的配置节组对象实例。
        /// </summary>
        /// <typeparam name="TSectionGroup">继承自<see cref="ConfigurationSectionGroup"/>的类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <returns><typeparamref name="TSectionGroup"/>类型的配置节组对象实例。</returns>
        public override TSectionGroup GetSectionGroupInUserConfig<TSectionGroup>(string sectionGroupName)
        {
            string filePath = string.Empty;
            return this.GetSectionGroupInUserConfig<TSectionGroup>(sectionGroupName, out filePath);
        }

        /// <summary>
        /// 从用户自定义配置文件中获取名称为<paramref name="sectionGroupName"/>的配置节组对象实例。
        /// </summary>
        /// <typeparam name="TSectionGroup">继承自<see cref="ConfigurationSectionGroup"/>的类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <param name="userConfigPath">用户自定义配置文件路径。</param>
        /// <returns><typeparamref name="TSectionGroup"/>类型的配置节组对象实例。</returns>
        protected virtual TSectionGroup GetSectionGroupInUserConfig<TSectionGroup>(string sectionGroupName, out string userConfigPath)
            where TSectionGroup : ConfigurationSectionGroup
        {
            userConfigPath = string.Empty;
            try
            {
                Config configuration = this.GetUserConfiguration(sectionGroupName, out userConfigPath, true);
                if (configuration.IsNull())
                {
                    return null;
                }
                else
                {
                    ConfigurationSectionGroup sectionGroup = configuration.SectionGroups[sectionGroupName];
                    return sectionGroup.IsNull() ? null : sectionGroup.ForceTo<TSectionGroup>();
                }
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region GetSection
        /// <summary>
        /// 获取<typeparamref name="TSection"/>类型的<see cref="ConfigurationSectionResult{TSection}"/>对象实例。
        /// </summary>
        /// <typeparam name="TSection">继承自<see cref="ConfigurationSection"/>的类型。</typeparam>
        /// <param name="sectionName">自定义配置节名称。</param>
        /// <returns><typeparamref name="TSection"/>类型的<see cref="ConfigurationSectionResult{TSection}"/>对象实例。</returns>
        public override ConfigurationSectionResult<TSection> GetSection<TSection>(string sectionName)
        {
            ConfigurationSectionResult<TSection> result = this.FindInCacheService<ConfigurationSectionResult<TSection>>(sectionName);
            if (result.IsNull())
            {
                List<string> dependencies = new List<string>();
                string devlibConfigPath = string.Empty;
                string userConfigPath = string.Empty;
                result = new ConfigurationSectionResult<TSection>(sectionName)
                {
                    ConfigurationSectionInAppConfig = this.GetSectionInAppConfig<TSection>(sectionName),
                    ConfigurationSectionInDevLibConfig = this.GetSectionInDevLibConfig<TSection>(sectionName, out devlibConfigPath),
                    ConfigurationSectionInUserConfig = this.GetSectionInUserConfig<TSection>(sectionName, out userConfigPath)
                };
                dependencies.Add(Path.Combine(AspContextVariables.Context.ApplicationPhysicalDirectory, "web.config"));
                if (!devlibConfigPath.IsEmptyOrWriteSpaces()) dependencies.Add(devlibConfigPath);
                if (!userConfigPath.IsEmptyOrWriteSpaces()) dependencies.Add(userConfigPath);
                this.SaveInCacheService(sectionName, result, dependencies.ToArray());
            }
            return result;
        }
        #endregion

        #region GetSectionGroup
        /// <summary>
        /// 获取<typeparamref name="TSectionGroup"/>类型的<see cref="ConfigurationSectionGroupResult{T}"/>对象实例。
        /// </summary>
        /// <typeparam name="TSectionGroup">配置节组类型。</typeparam>
        /// <param name="sectionGroupName">配置节组名称。</param>
        /// <returns><typeparamref name="TSectionGroup"/>类型的<see cref="ConfigurationSectionGroupResult{T}"/>对象实例。</returns>
        public override ConfigurationSectionGroupResult<TSectionGroup> GetSectionGroup<TSectionGroup>(string sectionGroupName)
        {
            ConfigurationSectionGroupResult<TSectionGroup> result = this.FindInCacheService<ConfigurationSectionGroupResult<TSectionGroup>>(sectionGroupName);
            if (result.IsNull())
            {
                List<string> dependencies = new List<string>();
                string devlibConfigPath = string.Empty;
                string userConfigPath = string.Empty;
                result = new ConfigurationSectionGroupResult<TSectionGroup>(sectionGroupName)
                {
                    ConfigurationSectionGroupInAppConfig = this.GetSectionGroupInAppConfig<TSectionGroup>(sectionGroupName),
                    ConfigurationSectionGroupInDevLibConfig = this.GetSectionGroupInDevLibConfig<TSectionGroup>(sectionGroupName, out devlibConfigPath),
                    ConfigurationSectionGroupInUserConfig = this.GetSectionGroupInUserConfig<TSectionGroup>(sectionGroupName, out userConfigPath)
                };
                dependencies.Add(Path.Combine(AspContextVariables.Context.ApplicationPhysicalDirectory, "web.config"));
                if (!devlibConfigPath.IsEmptyOrWriteSpaces()) dependencies.Add(devlibConfigPath);
                if (!userConfigPath.IsEmptyOrWriteSpaces()) dependencies.Add(userConfigPath);
                this.SaveInCacheService(sectionGroupName, result, dependencies.ToArray());
            }
            return result;
        }
        #endregion
    }
}

#region README

/*
 * ####     ©2014 Wang Yucai
 * 
 * ####     Contact me
 *                  
 *                  E-mail : Masterduner@Yeah.net
 *                  Mobile : 13621384677
 *                  QQ : 180261899
 */

#endregion